package su.theravada.jpalireader;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JToolBar;
import javax.swing.ListSelectionModel;

import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.WindowConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JTextField;
import javax.swing.ListModel;

import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.queryParser.QueryParser.Operator;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopScoreDocCollector;
import org.apache.lucene.search.highlight.Formatter;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.NullFragmenter;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import org.apache.lucene.search.regex.RegexQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.SimpleFSDirectory;
import org.apache.lucene.util.Version;
import org.lobobrowser.html.gui.HtmlPanel;
import org.lobobrowser.html.test.SimpleHtmlRendererContext;
import org.lobobrowser.html.test.SimpleUserAgentContext;
import org.lobobrowser.html.test.SimpleHtmlRendererContext;

import su.theravada.jpalireader.IndexingProgressDlg.IndexObjectType;
import su.theravada.jpalireader.entities.CollectionInfo;
import su.theravada.jpalireader.entities.NodeInfo;
import su.theravada.jpalireader.openBookDlg.OpenBookDlg;
import su.theravada.jpalireader.util.PaliUtil;
import su.theravada.jpalireader.util.SqlUtil;
import su.theravada.jpalireader.util.UTF8Control;
import su.theravada.jpalireader.util.ZipUtil;


/**
* This code was edited or generated using CloudGarden's Jigloo
* SWT/Swing GUI Builder, which is free for non-commercial
* use. If Jigloo is being used commercially (ie, by a corporation,
* company or business for any purpose whatever) then you
* should purchase a license for each developer using Jigloo.
* Please visit www.cloudgarden.com for details.
* Use of Jigloo implies acceptance of these licensing terms.
* A COMMERCIAL LICENSE HAS NOT BEEN PURCHASED FOR
* THIS MACHINE, SO JIGLOO OR THIS CODE CANNOT BE USED
* LEGALLY FOR ANY CORPORATE OR COMMERCIAL PURPOSE.
*/
public class TipitakaSearchPanel extends JSplitPane {
	private JTextField ctlSearchBox;
	private JCheckBox ctlIgnoreDiac;
	private JCheckBox ctlHighlightExact;
	private PaliComboBox ctlPaliEntry;
	private JSplitPane ctlVertSplitter;
	private HtmlPanel ctlResultDocument;
	private JScrollPane ctlMatchedBooksScroll;
	private JList ctlMatchedBooks;
	private JComboBox ctlSearchScope;
	private JButton ctlSearch;
	private JPanel ctlTopPanel;
	private JLabel ctlBookLocation;
	private int _ResultCount;
	private int _CurrentResult;
	private JToolBar ctlToolBar;
	private JButton ctlLastMatch;
	private JButton ctlNextMatch;
	private JButton ctlPrevMatch;
	private JButton ctlFirstMatch;
	private JPanel ctlRightFrame;
	
	public TipitakaSearchPanel() {
		super();
		
		initGUI();
		FillData();
	}
	
	private void initGUI() {
		try {
			this.setPreferredSize(new java.awt.Dimension(847, 594));			
			this.setLayout(null);
			ResourceBundle res_strings = ResourceBundle.getBundle("strings", Locale.getDefault(),new UTF8Control());
			
			{
				this.setBounds(0, 504, 178, 24);
				setOrientation(JSplitPane.VERTICAL_SPLIT);
			}
			{
				ctlVertSplitter = new JSplitPane();
				ctlVertSplitter.setBounds(12, 545, 178, 24);
			}
			setBottomComponent(ctlVertSplitter);						
			{
				ctlTopPanel=new JPanel();
				ctlTopPanel.setLayout(null);
				setTopComponent(ctlTopPanel);
			}			
			{
				ctlSearchBox = new JTextField();
				ctlTopPanel.add(ctlSearchBox);
				ctlSearchBox.setBounds(7, 12, 277, 22);
			}
			{
				ctlSearch = new JButton();
				ctlTopPanel.add(ctlSearch);
				ctlSearch.setText(res_strings.getString("Search"));
				ctlSearch.setBounds(329, 12, 100, 22);
				ctlSearch.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent evt) {
						ctlSearchActionPerformed(evt);
					}
				});
			}
			{
				ctlSearchScope = new JComboBox();
				ctlTopPanel.add(ctlSearchScope);				
				ctlSearchScope.setBounds(468, 11, 367, 22);
			}
			{
				ctlIgnoreDiac = new JCheckBox();
				ctlTopPanel.add(ctlIgnoreDiac);
				ctlIgnoreDiac.setText(res_strings.getString("IgnorePaliDiac"));
				ctlIgnoreDiac.setBounds(7, 38, 272, 19);
				
				ctlIgnoreDiac.addChangeListener(new ChangeListener() {

					@Override
					public void stateChanged(ChangeEvent arg0) {
						ctlHighlightExact.setSelected(!ctlIgnoreDiac.isSelected());
						ctlHighlightExact.setEnabled(!ctlIgnoreDiac.isSelected());						
					}});
			}
			{
				ctlHighlightExact=new JCheckBox();
				ctlTopPanel.add(ctlHighlightExact);
				ctlHighlightExact.setText(res_strings.getString("HighlightExact"));
				ctlHighlightExact.setBounds(290, 38, 272, 19);
				ctlHighlightExact.setSelected(true);
			}			
			{
				ctlPaliEntry = new PaliComboBox();
				ctlTopPanel.add(ctlPaliEntry);
				ctlPaliEntry.setBounds(290, 12, 33, 22);
				ctlPaliEntry.setTextField(ctlSearchBox);
			}
			{
				ctlBookLocation=new JLabel();
				ctlTopPanel.add(ctlBookLocation);
				ctlBookLocation.setBounds(7,60,700,22);
			}			
			{
				ctlMatchedBooksScroll = new JScrollPane();
				ctlMatchedBooksScroll.setBounds(7, 66, 317, 371);
				{
					ctlMatchedBooks = new JList();
					ctlMatchedBooksScroll.setViewportView(ctlMatchedBooks);
					ctlMatchedBooks.setBounds(7, 81, 277, 348);
					ctlMatchedBooks.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
					ctlMatchedBooks.addListSelectionListener(new ListSelectionListener() {
						public void valueChanged(ListSelectionEvent evt) {
							ctlMatchedBooksValueChanged(evt);
						}
					});
					
					ctlMatchedBooks.addMouseListener(new MouseListener() {

						@Override
						public void mouseClicked(MouseEvent arg0) {
							ctlMatchedBooksMouseClicked(arg0);
						}

						@Override
						public void mouseEntered(MouseEvent arg0) {}

						@Override
						public void mouseExited(MouseEvent arg0) {}

						@Override
						public void mousePressed(MouseEvent arg0) {}

						@Override
						public void mouseReleased(MouseEvent arg0) {}
						});
				}
				ctlVertSplitter.setLeftComponent(ctlMatchedBooksScroll);
			}
			
			ctlRightFrame=new JPanel();
			ctlVertSplitter.setRightComponent(ctlRightFrame);	
			{
				ctlResultDocument = new HtmlPanel();
			}			
			
			ctlToolBar = new JToolBar();
			//ctlRightFrame.add(ctlToolBar, BorderLayout.NORTH);
			ctlToolBar.setFloatable(false);
			ctlToolBar.setVisible(false);			
			{
				ctlFirstMatch = new JButton();
				ctlToolBar.add(ctlFirstMatch);
				ctlFirstMatch.setText(res_strings.getString("First"));
			}
			{
				ctlPrevMatch = new JButton();
				ctlToolBar.add(ctlPrevMatch);
				ctlPrevMatch.setText(res_strings.getString("Prev"));
			}
			{
				ctlNextMatch = new JButton();
				ctlToolBar.add(ctlNextMatch);
				ctlNextMatch.setText(res_strings.getString("Next"));
			}
			{
				ctlLastMatch = new JButton();
				ctlToolBar.add(ctlLastMatch);
				ctlLastMatch.setText(res_strings.getString("Last"));
			}
			
			GroupLayout thisLayout = new GroupLayout(ctlRightFrame);
			ctlRightFrame.setLayout(thisLayout);
			
			thisLayout.setVerticalGroup(thisLayout.createSequentialGroup()
					.addComponent(ctlToolBar, GroupLayout.PREFERRED_SIZE, 35, GroupLayout.PREFERRED_SIZE)
					.addComponent(ctlResultDocument, 0, 284, Short.MAX_VALUE));
			thisLayout.setHorizontalGroup(thisLayout.createParallelGroup()
				.addComponent(ctlToolBar, GroupLayout.Alignment.LEADING, 0, 767, Short.MAX_VALUE)
				.addComponent(ctlResultDocument, GroupLayout.Alignment.LEADING, 0, 767, Short.MAX_VALUE));			
			
		    //search functions
		    ctlFirstMatch.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent arg0) {
					ctlResultDocument.scrollToElement("sr1");
					ctlResultDocument.scrollBy(0,1);	
					_CurrentResult=1;
				}	    	
		    });
		    
		    ctlLastMatch.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent arg0) {
					ctlResultDocument.scrollToElement("sr"+_ResultCount);
					ctlResultDocument.scrollBy(0, 1);	
					_CurrentResult=_ResultCount;
				}	    	
		    });
		    
		    ctlPrevMatch.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent arg0) {
					if(_CurrentResult!=1)
					{
						_CurrentResult=_CurrentResult==0 ? 1 : _CurrentResult-1;
											
						ctlResultDocument.scrollToElement("sr"+_CurrentResult);
						ctlResultDocument.scrollBy(0, 1);
					}
				}	    	
		    });
		    
		    ctlNextMatch.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent arg0) {
					if(_CurrentResult!=_ResultCount)
					{
						_CurrentResult=_CurrentResult==0 ? 1 : _CurrentResult+1;
											
						ctlResultDocument.scrollToElement("sr"+_CurrentResult);
						ctlResultDocument.scrollBy(0, 1);
					}
				}	    	
		    });
				
		    ctlSearchBox.addKeyListener(new KeyListener() {
				@Override
				public void keyPressed(KeyEvent arg0) {}

				@Override
				public void keyReleased(KeyEvent arg0) {
					if(arg0.getKeyCode()==KeyEvent.VK_ENTER)
						ctlSearchActionPerformed(null);
				}

				@Override
				public void keyTyped(KeyEvent arg0) {}				    	
		    });
		    
		    
			setDividerLocation(80);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private void FillData()
	{
		ResourceBundle res_strings = ResourceBundle.getBundle("strings", Locale.getDefault(),new UTF8Control());
		
		ResultSet rsParents = null;
		ResultSet rsChildren = null;
        PreparedStatement psSelectParents = null;
        PreparedStatement psSelectChildren = null;
    	ArrayList<CollectionInfo> arrCollections=new ArrayList<CollectionInfo>();
    	
        try
        {
        	psSelectParents=MainWindow.getDBConnection().prepareStatement("SELECT collectionid,title FROM collections WHERE parentid IS NULL AND hasptspages=true");
        	rsParents=psSelectParents.executeQuery();
        	
        	psSelectChildren=MainWindow.getDBConnection().prepareStatement("SELECT collectionid,title,hasptspages FROM collections WHERE parentid=? AND hasptspages=true");
        	
        	while(rsParents.next())
        	{
        		arrCollections.add(new CollectionInfo(rsParents.getInt("collectionid"),
        				rsParents.getString("title"),false,0));
        		
        		psSelectChildren.setInt(1, rsParents.getInt("collectionid"));
        		rsChildren=psSelectChildren.executeQuery();
        		while(rsChildren.next())
        		{
            		arrCollections.add(new CollectionInfo(rsChildren.getInt("collectionid"),
            				rsChildren.getString("title"),rsChildren.getBoolean("hasptspages"),
            				rsParents.getInt("collectionid")));        			
        		}
        		
        		SqlUtil.CloseResultSet(rsChildren);
        	}     
        	
        	arrCollections.add(0,new CollectionInfo(-2,res_strings.getString("CollectionPED"),false));
        	arrCollections.add(0,new CollectionInfo(-1,res_strings.getString("CollectionAllBooks"),false));
        	
        	ComboBoxModel ctlSelectCollectionModel = 
        		new DefaultComboBoxModel(arrCollections.toArray());
        	ctlSearchScope.setModel(ctlSelectCollectionModel);
		}
		catch(SQLException sqle)
		{		
			SqlUtil.ReportSQLException(sqle);
		}
		catch(Exception ex)
		{		
			ex.printStackTrace();					
		}
		finally
		{
			SqlUtil.ClosePreparedStatement(psSelectParents);
			SqlUtil.CloseResultSet(rsParents);
			SqlUtil.ClosePreparedStatement(psSelectChildren);
			SqlUtil.CloseResultSet(rsChildren);			
		}
	}
	
	
	private void ctlSearchActionPerformed(ActionEvent evt) 
	{
		try
		{
	    	ctlBookLocation.setText("");
	    	
			ctlToolBar.setVisible(false);
			SimpleHtmlRendererContext rcontext=new SimpleHtmlRendererContext(ctlResultDocument, new SimpleUserAgentContext());
			ctlResultDocument.setHtml("", "file:///"+System.getProperty("user.dir")+"/", rcontext);
			 
			if(((CollectionInfo)ctlSearchScope.getSelectedItem()).getCollectionID()==-2)
			{	
				FSDirectory objIndexDir=FSDirectory.open(new File(Paths.PEDIndexPath));
				if(IndexReader.indexExists(objIndexDir))
				{
					SearchPED();
				}
				else
				{
		            ResourceBundle res_strings = ResourceBundle.getBundle("strings", Locale.getDefault(),new UTF8Control());
		            
		            Object[] options = {res_strings.getString("Yes"),
		            		res_strings.getString("No")};
		            
		            int nDialogResult = JOptionPane.showOptionDialog(getTopLevelAncestor(),
							res_strings.getString("IndexPEDConfirm"),
							res_strings.getString("Confirm"),
						    JOptionPane.YES_NO_OPTION,
						    JOptionPane.QUESTION_MESSAGE,
						    null,     //do not use a custom Icon
						    options,  //the titles of buttons
						    options[0]);
					
		            if(nDialogResult==JOptionPane.YES_OPTION)
		            {    
		            	IndexingProgressDlg objDlg=new IndexingProgressDlg((JFrame)getTopLevelAncestor(),IndexObjectType.PED);
		            	objDlg.setSize(388,135);
		            	objDlg.setLocationRelativeTo(null);
		            	objDlg.setVisible(true);
		            	
		            	if(objDlg.DialogSuccess)
		            	{
							SearchPED();
		            	}
		            }
				}							
			}
			else
			{
				FSDirectory objIndexDir=FSDirectory.open(new File(Paths.CanonIndexPath));
				if(IndexReader.indexExists(objIndexDir))
				{
					SearchCanon();
				}
				else
				{
		            ResourceBundle res_strings = ResourceBundle.getBundle("strings", Locale.getDefault(),new UTF8Control());
		            
		            Object[] options = {res_strings.getString("Yes"),
		            		res_strings.getString("No")};
		            
		            int nDialogResult = JOptionPane.showOptionDialog(getTopLevelAncestor(),
							res_strings.getString("IndexCanonConfirm"),
							res_strings.getString("Confirm"),
						    JOptionPane.YES_NO_OPTION,
						    JOptionPane.QUESTION_MESSAGE,
						    null,     //do not use a custom Icon
						    options,  //the titles of buttons
						    options[0]);
					
		            if(nDialogResult==JOptionPane.YES_OPTION)
		            {    
		            	IndexingProgressDlg objDlg=new IndexingProgressDlg((JFrame)getTopLevelAncestor(),IndexObjectType.PALICANON);
		            	objDlg.setSize(388,135);
		            	objDlg.setLocationRelativeTo(null);
		            	objDlg.setVisible(true);
		            	
		            	if(objDlg.DialogSuccess)
		            	{
							SearchCanon();
		            	}
		            }
				}	
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
	
	private void SearchCanon()
	{		
		setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));	
		
		try 
		{
			FSDirectory objIndexDir= FSDirectory.open(new File(Paths.CanonIndexPath));
			IndexReader objIndexReader=IndexReader.open(objIndexDir);	
			IndexSearcher objSearcher=new IndexSearcher(objIndexReader);
		
			BooleanQuery objFinalQuery=new BooleanQuery();
			
			
			if(((CollectionInfo)ctlSearchScope.getSelectedItem()).getCollectionID()!=-1)
			{
				BooleanQuery objBookQuery=new BooleanQuery();
				
				ArrayList<Integer> arrSearchFile=GetSearchFiles(((CollectionInfo)ctlSearchScope.getSelectedItem()));
				
				for(int FileID : arrSearchFile)
				{
					Query objTermQuery=NumericRangeQuery.newIntRange("file",FileID,FileID,true,true);
					objBookQuery.add(objTermQuery,BooleanClause.Occur.SHOULD);					
				}
				
				objFinalQuery.add(objBookQuery,BooleanClause.Occur.MUST);				
			}						
						
			Query objTextQuery=null;
			
			if(ctlIgnoreDiac.isSelected())
			{
				objTextQuery=new RegexQuery(new Term("text",PaliUtil.ConvertToRegex(ctlSearchBox.getText().trim())));			
			}
			else
			{
				QueryParser qp=new QueryParser(Version.LUCENE_36,"text",new StandardAnalyzer(Version.LUCENE_36,PaliUtil.getPaliStopWords()));
				qp.setAllowLeadingWildcard(true);
				qp.setDefaultOperator(Operator.AND);
				objTextQuery=qp.parse(ctlSearchBox.getText().trim());
			}
			
			objFinalQuery.add(objTextQuery,BooleanClause.Occur.MUST);		
			
			Query objRewritten=objFinalQuery.rewrite(objIndexReader);
						
			TopScoreDocCollector collector = TopScoreDocCollector.create(300,true);
			objSearcher.search(objRewritten,collector);
			ScoreDoc[] hits=collector.topDocs().scoreDocs;
			
			DisplayCanonHits(hits,objSearcher);
						
			objSearcher.close();
			objIndexDir.close();
			
			if(hits.length==0)
			{
	            ResourceBundle res_strings = ResourceBundle.getBundle("strings", Locale.getDefault(),new UTF8Control());
	            ctlBookLocation.setText(res_strings.getString("NoMatches"));
	            ctlBookLocation.setForeground(Color.red);
			}
		} 
		catch (IOException e) 
		{			
			e.printStackTrace();
		} 
		catch (ParseException e) 
		{
			e.printStackTrace();
		}	
		finally
		{
			setCursor(Cursor.getDefaultCursor());
		}
	}
	
	private void SearchPED()
	{
		setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));	
		
		try 
		{
			FSDirectory objIndexDir= FSDirectory.open(new File(Paths.PEDIndexPath));
			IndexReader objIndexReader=IndexReader.open(objIndexDir);	
			IndexSearcher objSearcher=new IndexSearcher(objIndexReader);
			
			Query objTextQuery=null;
			
			if(ctlIgnoreDiac.isSelected())
			{
				objTextQuery=new RegexQuery(new Term("text",PaliUtil.ConvertToRegex(ctlSearchBox.getText().trim())));			
			}
			else
			{
				QueryParser qp=new QueryParser(Version.LUCENE_36,"text",new StandardAnalyzer(Version.LUCENE_36,PaliUtil.getPaliStopWords()));
				qp.setAllowLeadingWildcard(true);
				qp.setDefaultOperator(Operator.AND);
				objTextQuery=qp.parse(ctlSearchBox.getText().trim());
			}
			
			TopScoreDocCollector collector = TopScoreDocCollector.create(300,true);
			objSearcher.search(objTextQuery,collector);
			ScoreDoc[] hits=collector.topDocs().scoreDocs;
			
			DisplayPEDHits(hits,objSearcher);	
			objSearcher.close();
			objIndexDir.close();
			
			if(hits.length==0)
			{
	            ResourceBundle res_strings = ResourceBundle.getBundle("strings", Locale.getDefault(),new UTF8Control());
	            ctlBookLocation.setText(res_strings.getString("NoMatches"));
	            ctlBookLocation.setForeground(Color.red);
			}
		} 
		catch (IOException e) 
		{			
			e.printStackTrace();
		} 
		catch (ParseException e) 
		{
			e.printStackTrace();
		}	
		finally
		{
			setCursor(Cursor.getDefaultCursor());
		}		
	}
	
	private ArrayList<Integer> GetSearchFiles(CollectionInfo objCollection)
	{
		ArrayList<Integer> arrRetVal=new ArrayList<Integer>();
		
		PreparedStatement psSelectFiles=null;
		ResultSet rsFiles=null;
		
		PreparedStatement psChildCollections=null;
		ResultSet rsChildCollections=null;
		
		try
		{
			psSelectFiles=MainWindow.getDBConnection().prepareStatement("SELECT fileid FROM files WHERE CollectionID=?");
			psSelectFiles.setInt(1,objCollection.getCollectionID());
			rsFiles=psSelectFiles.executeQuery();
			
			if(objCollection.getParentID()==0)
			{
				psChildCollections=MainWindow.getDBConnection().prepareStatement("SELECT collectionid FROM collections WHERE parentid=?");
				psChildCollections.setInt(1,objCollection.getCollectionID());
				rsChildCollections=psChildCollections.executeQuery();
				
				while(rsChildCollections.next())
				{
					psSelectFiles.setInt(1,rsChildCollections.getInt("collectionid"));
					rsFiles=psSelectFiles.executeQuery();
					
					while(rsFiles.next())
						arrRetVal.add(rsFiles.getInt("fileid"));
				}
			}
			else
			{
				while(rsFiles.next())
					arrRetVal.add(rsFiles.getInt("fileid"));
			}
		}
		catch(SQLException sqle)
		{		
			SqlUtil.ReportSQLException(sqle);
		}
		catch(Exception ex)
		{		
			ex.printStackTrace();					
		}
		finally
		{
			SqlUtil.ClosePreparedStatement(psSelectFiles);
			SqlUtil.CloseResultSet(rsFiles);	
			SqlUtil.ClosePreparedStatement(psChildCollections);
			SqlUtil.CloseResultSet(rsChildCollections);				
		}
		
		return arrRetVal;
	}
	
	private void DisplayPEDHits(ScoreDoc[] hits,IndexSearcher objSearcher)
	{
		try 
		{
			ArrayList<DictionaryMatch> arrMatchedDic=new ArrayList<DictionaryMatch>();
			
			for(ScoreDoc objHit : hits)
			{
				Document objDoc=objSearcher.doc(objHit.doc);
				
				arrMatchedDic.add(new DictionaryMatch(Integer.parseInt(objDoc.get("ID")),objDoc.get("letter")));            		            		                 					
			}

			ListModel ctlMatchedDicModel = new DefaultComboBoxModel(arrMatchedDic.toArray());
			ctlMatchedBooks.setModel(ctlMatchedDicModel);
		} 
		catch (CorruptIndexException e) 
		{
			e.printStackTrace();
		} 
		catch (IOException e) 
		{
			e.printStackTrace();
		}		
		catch(Exception ex)
		{		
			ex.printStackTrace();					
		}
	}
	
	private void DisplayCanonHits(ScoreDoc[] hits,IndexSearcher objSearcher)
	{
        PreparedStatement psParent = null;
        ResultSet rsParent=null;
        
		try 
		{
			ArrayList<NodeInfo> arrMatchedBooks=new ArrayList<NodeInfo>();
			
			for(ScoreDoc objHit : hits)
			{
				Document objDoc=objSearcher.doc(objHit.doc);
				
            	psParent=MainWindow.getDBConnection().prepareStatement("SELECT nodeid,nodetitle FROM nodes WHERE FileID=? ORDER BY ParentID FETCH FIRST ROW ONLY");
            	psParent.setInt(1, Integer.parseInt(objDoc.get("file")));
            	rsParent=psParent.executeQuery();
            	if(rsParent.next())
            		arrMatchedBooks.add(new NodeInfo(rsParent.getInt("nodeid"),rsParent.getString("nodetitle"),0));            		            		                 					
			}

			ListModel ctlMatchedBooksModel = new DefaultComboBoxModel(arrMatchedBooks.toArray());
			ctlMatchedBooks.setModel(ctlMatchedBooksModel);
		} 
		catch (CorruptIndexException e) 
		{
			e.printStackTrace();
		} 
		catch (IOException e) 
		{
			e.printStackTrace();
		}		
		catch(SQLException sqle)
		{		
			SqlUtil.ReportSQLException(sqle);
		}
		catch(Exception ex)
		{		
			ex.printStackTrace();					
		}
		finally
		{
			SqlUtil.ClosePreparedStatement(psParent);
			SqlUtil.CloseResultSet(rsParent);			
		}
	}
	
	private void ctlMatchedBooksMouseClicked(MouseEvent arg0)
	{
		if (arg0.getClickCount() == 2 && !arg0.isConsumed()) {

			arg0.consume();
		    //handle double click. 
			if(((CollectionInfo)ctlSearchScope.getSelectedItem()).getCollectionID()!=-2)
			{
				int NodeID=((NodeInfo)ctlMatchedBooks.getSelectedValue()).getNodeID();
				((MainWindow)getTopLevelAncestor()).OpenBook(NodeID, 0, "", 0);
			}
		}
	}
	
	private void ctlMatchedBooksValueChanged(ListSelectionEvent evt) 
	{
		ResourceBundle res_strings = ResourceBundle.getBundle("strings", Locale.getDefault(),new UTF8Control());
		
		String strDocumentFileName="";
        String strArchiveFileName="";
        String strIndexPath="";
        boolean bShowBold=true,bShowFont=true;
        
		if(((CollectionInfo)ctlSearchScope.getSelectedItem()).getCollectionID()==-2)
		{
			strDocumentFileName=((DictionaryMatch)ctlMatchedBooks.getSelectedValue()).getID();
			strArchiveFileName=Paths.PEDPath;
			strIndexPath=Paths.PEDIndexPath;
			ctlBookLocation.setText("");
		}
		else
		{
	        ResultSet rs = null;
	        PreparedStatement psSelect = null;
			try
			{			
	            psSelect=MainWindow.getDBConnection().prepareStatement("SELECT files.FileName,nodes.nodetitle,files.FileID,nodes.BookmarkName,files.showbold,files.showfont FROM files INNER JOIN nodes ON files.FileID=nodes.FileID WHERE NodeID=?");
	            psSelect.setInt(1, ((NodeInfo)ctlMatchedBooks.getSelectedValue()).getNodeID());
	            
	            rs = psSelect.executeQuery();
	            if(rs.next())
	            {
	            	strDocumentFileName=rs.getString("FileName");
	            	bShowBold=rs.getBoolean("ShowBold");
	            	bShowFont=rs.getBoolean("ShowFont");
	            }                         
			}
			catch(SQLException sqle)
			{		
				SqlUtil.ReportSQLException(sqle);
			}
			catch(Exception ex)
			{		
				ex.printStackTrace();					
			}
			finally
			{
				SqlUtil.ClosePreparedStatement(psSelect);
				SqlUtil.CloseResultSet(rs);		
			}
			
			strArchiveFileName=Paths.CanonPath;
			strIndexPath=Paths.CanonIndexPath;
		}
		
		String strFileContent=ZipUtil.LoadContentFile(strDocumentFileName,strArchiveFileName,bShowBold,bShowFont);								
	    SimpleHtmlRendererContext rcontext=new SimpleHtmlRendererContext(ctlResultDocument, new SimpleUserAgentContext());	
		
	    if(((CollectionInfo)ctlSearchScope.getSelectedItem()).getCollectionID()!=-2)
	    {
            ctlBookLocation.setForeground(Color.black);
	    	ctlBookLocation.setText(res_strings.getString("BookLocation")+((NodeInfo)ctlMatchedBooks.getSelectedValue()).getPath());
	    }
	    
	    setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));	
	    
	    try
	    {
	    	String strFragments="";
	    	
	    	if(ctlHighlightExact.isSelected() && !ctlIgnoreDiac.isSelected())
	    	{
	    		String strPhrase=ctlSearchBox.getText().trim().replace("\"", "");
	    		strFragments=strFileContent.replace(strPhrase,"<a name=\"srBkm23\" class=\"sresult\">"+
	    				strPhrase+"</a>");
	    	}
	    	else
	    	{
				Query objTextQuery=null;
				
				if(ctlIgnoreDiac.isSelected())
				{
					objTextQuery=new RegexQuery(new Term("text",PaliUtil.ConvertToRegex(ctlSearchBox.getText().trim())));				
				}
				else
				{
					QueryParser qp=new QueryParser(Version.LUCENE_36,"text",new StandardAnalyzer(Version.LUCENE_36,PaliUtil.getPaliStopWords()));
					qp.setAllowLeadingWildcard(true);
					qp.setDefaultOperator(Operator.AND);
					objTextQuery=qp.parse(ctlSearchBox.getText().trim());
				}
						
				FSDirectory objIndexDir= FSDirectory.open(new File(strIndexPath));
				IndexReader objIndexReader=IndexReader.open(objIndexDir);	
				
				QueryScorer scorer = new QueryScorer(objTextQuery);
				
	            Formatter formatter = new SimpleHTMLFormatter("<a name=\"srBkm23\" class=\"sresult\">", "</a>");
	            
	            Highlighter highlighter = new Highlighter(formatter, scorer);
	            highlighter.setTextFragmenter(new NullFragmenter());
	
	            TokenStream stream = new StandardAnalyzer(Version.LUCENE_36).tokenStream("text", new StringReader(strFileContent));
	            highlighter.setMaxDocCharsToAnalyze(3000000);
	            strFragments = highlighter.getBestFragments(stream, strFileContent, 100, "<hr/>");
	    	        	        	       	       	   
	            objIndexReader.close();
	    	}
	    	
            _CurrentResult=0;
            _ResultCount=0;
            
			Matcher objReplaceMatcher=Pattern.compile("srBkm23",Pattern.CASE_INSENSITIVE).matcher(strFragments);
			StringBuffer sb = new StringBuffer();
			while (objReplaceMatcher.find()) 
			{
				_ResultCount++;
				objReplaceMatcher.appendReplacement(sb, "sr"+_ResultCount);
			}
			objReplaceMatcher.appendTail(sb);
            
			ctlResultDocument.setHtml(sb.toString(), "file:///"+System.getProperty("user.dir")+"/", rcontext);
			
            ctlBookLocation.setForeground(Color.black);
			ctlBookLocation.setText(res_strings.getString("MatchesCount")+_ResultCount+"  "+ctlBookLocation.getText());
			ctlToolBar.setVisible(true);
	    }
		catch (CorruptIndexException e) 
		{
			e.printStackTrace();
		} 
		catch (IOException e) 
		{
			e.printStackTrace();
		}		
		catch(Exception ex)
		{		
			ex.printStackTrace();					
		}	
		finally
		{
			setCursor(Cursor.getDefaultCursor());
		}
	}
		
	private class DictionaryMatch
	{
		int _ID;
		String _letter;
		
		public DictionaryMatch(int ID,String letter)
		{
			_ID=ID;
			_letter=letter;
		}
		
		public String getID()
		{
			return String.format("%02d", _ID);
		}
		
		public String toString()
		{
			return String.valueOf(_letter);
		}
	}
	
}
